#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include <string>
#include <fstream>
#include <streambuf>
#include <sstream>
#include <cstdlib>
#include <new>
#include <typeinfo>
#include <list>
#include <thread> // std::thread
#include <mutex>  // std::mutex

using namespace std;

// 参考: https://blog.csdn.net/misayaaaaa/article/details/53786215
// 参考: https://github.com/applenob/Cpp_Primer_Practice/blob/master/excersize/ch02.md

// chapter 2  变量和基本类型

// 1.
// 类型 int、long、long long 和 short 的区别是什么？无符号类型和带符号类型的区别是什么？
// float 和 double的区别是什么？
// C++ 规定 short 和 int 至少16位，long 至少32位，long long 至少64位。
//  带符号类型能够表示正数、负数和 0 ，而无符号类型只能够表示 0 和正整数

// 2. 计算按揭贷款时，对于利率、本金和付款分别应选择何种数据类型？说明你的理由
// 大概说的就是强制类型转换吧，在表达式内如果有了无符号数，那么你就得保证关于它的结果也是非负的，
// 这样的话，如果你给它一个负值，那么编译器会取模
// 使用double。需要进行浮点计算


<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp
3.
// 读程序写结果。
unsigned u = 10;
unsigned u2 = 42;
std::cout << u2 - u << std::endl;
std::cout << u - u2 << std::endl;
int i = 10;
int i2 = 42;
=======
// 3.
// 读程序写结果。

unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl;
std::cout << u - u2 << std::endl;
int i = 10, i2 = 42;
>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp
std::cout << i2 - i << std::endl;
std::cout << i - i2 << std::endl;
std::cout << i - u << std::endl;
std::cout << u - i << std::endl;

<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp
// 输出:
32
4294967264  // 而unsigned int在大部分编译器中该类型占4个字节，则最大值是2的32次方，为4294967296
=======
输出：

32
4294967264
>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp
32
-32
0
0

// 4.



// 5.
// 指出下述字面值的数据类型并说明每一组内几种字面值的区别:

// (a) 'a', L'a', "a", L"a"
// (b) 10, 10u, 10L, 10uL, 012, 0xC
// (c) 3.14, 3.14f, 3.14L
// (d) 10, 10u, 10., 10e-2
// 解：

// (a): 字符字面值，宽字符字面值，字符串字面值，宽字符串字面值。
// (b): 十进制整型，十进制无符号整型，十进制长整型，八进制整型，十六进制整型。
// (c): double, float, long double
// (d): 十进制整型，十进制无符号整型，double, double



// 6.
// 下面两组定义是否有区别，如果有，请叙述之:

// int month = 9, day = 7;
// int month = 09, day = 07;
// 解：

// 第一行定义的是十进制的整型，第二行定义的是八进制的整型。但是month变量有误，八进制不能直接写9




// 7.
// 下述字面值表示何种含义？它们各自的数据类型是什么？
(a) "Who goes with F\145rgus?\012"
(b) 3.14e1L
(c) 1024f
(d) 3.14L
// 解：
(a) Who goes with Fergus?(换行)，string 类型
(b) long double
(c) 无效，因为后缀f只能用于浮点字面量，而1024是整型。
(d) long double

// 8.
// 请利用转义序列编写一段程序，要求先输出 2M，然后转到新一行。修改程序使其先输出 2，然后输出制表符，再输出 M，最后转到新一行。
// 解：

#include <iostream>
int main()
{
   std::cout << 2 << "\115\012";
   std::cout << 2 << "\t\115\012";
   return 0;
}


// 9.
// 解释下列定义的含义，对于非法的定义，请说明错在何处并将其改正。
<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp

(a) std::cin >> int input_value;
(b) int i = { 3.14 };
(c) double salary = wage = 9999.99;
(d) int i = 3.14;
// 解：

(a): 应该先定义再使用。
int input_value = 0;
std::cin >> input_value;
(b): i强制类型转换成3 
    用列表初始化内置类型的变量时，如果存在丢失信息的风险，则编译器将报错。

=======

(a) std::cin >> int input_value;
(b) int i = { 3.14 };
(c) double salary = wage = 9999.99;
(d) int i = 3.14;
// 解：

(a): 应该先定义再使用。

int input_value = 0;
std::cin >> input_value;
(b): i强制类型转换成3 
    用列表初始化内置类型的变量时，如果存在丢失信息的风险，则编译器将报错。

>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp
double i = { 3.14 };
(c): 在这里wage是未定义的，应该在此之前将其定义。

double wage;
double salary = wage = 9999.99;
(d): 不报错，但是小数部分会被截断。

double i = 3.14;



// 10.
// 下列变量的初值分别是什么？
<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp

std::string global_str;
int global_int;
int main()
{
    int local_int;
    std::string local_str;
}
// 解：
=======

std::string global_str;
int global_int;
int main()
{
    int local_int;
    std::string local_str;
}
// 解：

global_str和global_int是全局变量，所以初值分别为空字符串和0
local_int是局部变量并且没有初始化，它的初值是未定义的
 local_str 是 string 类的对象，它的值由类确定，为空字符串
>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp

global_str和global_int是全局变量，所以初值分别为空字符串和0
local_int是局部变量并且没有初始化，它的初值是未定义的
local_str 是 string 类的对象，它的值由类确定，为空字符串

// C语言中未初始化的变量的值是0么
// 全局变量 、静态变量初始值为0
// 局部变量，自动变量初始值随机分配
// C语言中，定义局部变量时如果未初始化，则值是随机的，为什么？
// 定义局部变量，其实就是在栈中通过移动栈指针来给程序提供一个内存空间和这个局部变量名绑定。因为这段内存空间在栈上，而栈内存是反复使用的（脏的，上次用完没清零的），所以说使用栈来实现的局部变量定义时如果不显式初始化，值就是脏的

// 11.
<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp
指出下面的语句是声明还是定义:
=======
指出下面的语句是声明还是定义：
>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp

(a) extern int ix = 1024;
(b) int iy;
(c) extern int iz;
解：

(a): 定义 (b): 定义 (c): 声明


// 12.
// 请指出下面的名字中哪些是非法的？

// (a) int double = 3.14;
// (b) int _;
// (c) int catch-22;
// (d) int 1_or_2 = 1;
// (e) double Double = 3.14;
// 解：

// (a), (c), (d) 非法
// c:错误：无效字符“—”
// d:错误：不能以数字开头
// e:正确（但是不好）


// 13.
// 下面程序中j的值是多少？

int i = 42;
int main()
{
    int i = 100;
    int j = i;
}

<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp
// 新建局部变量会覆盖同名的全局变量
=======
新建局部变量会覆盖同名的全局变量
>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp
j=100

// 14.
// 下面的程序合法吗？如果合法，它将输出什么？

int i = 100, sum = 0;
for (int i = 0; i != 10; ++i)
    sum += i;
std::cout << i << " " << sum << std::endl;
解：

合法。输出是 100 45 。
显示访问i变量会访问到全局变量上  std::cout<<


// 15.
// 下面的哪个定义是不合法的？为什么？

// (a) int ival = 1.01;
// (b) int &rval1 = 1.01;
// (c) int &rval2 = ival;
// (d) int &rval3;

// (b)和(d)不合法，(b)引用必须绑定在对象上，(d)引用必须初始化
<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp
    int value = 10;
=======
int value = 10;
>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp
	int &My_value = value;   //引用，在定义引用的时候会将引用和它的初始值绑定在一起，而不是简单的赋值
	int My_value = 5;        //将5赋给了My_value和value
	int Her_value = My_value; //相当于将value赋给了Her_value
	int &My_value = 10;       //错误：引用类型的初始值必须是一个对象
	double vvalue = 40.6; 
	int &My_value = vvalue;   //错误：引用类型的初始值必须是int型对象

<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp
    所谓引用：它只是为存在的对象所起的另外一个名字。它不是一个对象，没有实际的地址,修改了引用也就修改了它指向的对象本身
=======
    所谓引用：它只是为存在的对象所起的另外一个名字。它不是一个对象，没有实际的地址
>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp



// 16.

// 考察下面的所有赋值然后回答：哪些赋值是不合法的？为什么？哪些赋值是合法的？它们执行了哪些操作？

// int i = 0, &r1 = i; 
// double d = 0, &r2 = d;
// (a) r2 = 3.14159;
// (b) r2 = r1;
// (c) i = r2;
// (d) r1 = d;
// 解：

// (a): 合法。给 d 赋值为 3.14159。
// (b): 合法。会执行自动转换（int->double）。
// (c): 合法。会发生小数截取。
// (d): 合法  强制类型转换


// 17.
// 所谓引用：它只是为存在的对象所起的另外一个名字。它不是一个对象，没有实际的地址。

// 	int value = 10;
// 	int &My_value = value;   //引用，在定义引用的时候会将引用和它的初始值绑定在一起，而不是简单的赋值
// 	int My_value = 5;        //将5赋给了My_value和value
// 	int Her_value = My_value; //相当于将value赋给了Her_value
// 	int &My_value = 10;       //错误：引用类型的初始值必须是一个对象
// 	double vvalue = 40.6; 
// 	int &My_value = vvalue;   //错误：引用类型的初始值必须是int型对象

// 执行下面的代码段将输出什么结果？

// int i, &ri = i;
// i = 5; ri = 10;
// std::cout << i << " " << ri << std::endl;
// 输出：10, 10




// 18.

// 先简单的了解一下指针：它和引用类似也实现了与其他对象之间的间接访问.
// 定义指针类型的变量通常是：int *P, P是变量名，加*号指的是其是一个int类型的指针。
// 指针类型也需要和匹配对象类型严格吻合
// int a;
// int* p1 = &a;   //初始值为a的地址
// int* p2 = p1;   //初始值为int类型对象的指针，也就是指针的指针

// 关键点（非常重要):
int i =10;
int& j = i;  //&符号紧随类型名出现，它是声明的一部分，j是一个引用
int* p;     //*符号紧随类型名出现，它是声明的一部分，p是一个指针
p = &i;    //&符号出现在表达式之中，是一个取地址符号
*p = i;    //*符号出现在表达式之中，是一个解引用符
int& j2 = *p;   //&是声明的一部分，*是解引用符

// 一定要注意到这两个符号的多重含义！！！

// 编写代码分别改变指针的值以及指针所指对象的值

    int a = 0;
    int b = 1;
    int* p1 = &a;
    int* p2 = p1;
    p1 = &b;  //改变了指针的值
    *p1 = b;   //改变指针所指对象的值


// 19.
// 主要区别上面讲的很清楚，这里总结一下:
// 1：指针本身就是一个对象，允许指针之间的拷贝和赋值，也可以在其生命周期指向不同的对象。而引用不行
// 2：指针无需在定义时赋值。
// 引用是另一个对象的别名，而指针本身就是一个对象。 引用必须初始化，并且一旦定义了引用就无法再绑定到其他对象。而指针无须在定义时赋初值，也可以重新赋值让其指向其他对象



// 20.
// 请叙述下面这段代码的作用。
int i = 42;
int* p1 = &i; 
*p1 = *p1 * *p1;
// 这段代码首先定义了一个int型的变量i，并赋初值42，随后定义了一个int型指针，初始值为i的地址，
// *P在表达式中，指的就是解操作符，而中间的*是乘的意思，所以作用就是将i改变为42*42。
// 要注意的就是*这个符号的多重含义

// 21.
// 请解释下述定义。在这些定义中有非法的吗？如果有，为什么？

// int i = 0;
// (a) double* dp = &i;
// (b) int* ip = i;
// (c) int* p = &i;
// 解：

// (a): 非法。不能将一个指向 double 的指针指向 int
// (b): 非法。不能将 int 变量赋给指针
// (c): 合法



// 22.
// 假设 p 是一个 int 型指针，请说明下述代码的含义
// if (p) // ...
// if (*p) // ...
// 解：
// 第一句判断 p 是不是一个空指针, 第二句判断 p 所指向的对象的值是不是为0



// 23.
<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp
// 给定指针 p，你能知道它是否指向了一个合法的对象吗？如果能，叙述判断的思路；如果不能，也请说明原因。
// 解：
// 不能，因为首先要确定这个指针是不是合法的，才能判断它所指向的对象是不是合法的
=======
给定指针 p，你能知道它是否指向了一个合法的对象吗？如果能，叙述判断的思路；如果不能，也请说明原因。

解：

不能，因为首先要确定这个指针是不是合法的，才能判断它所指向的对象是不是合法的
>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp


// 24.
// 在下面这段代码中为什么 p 合法而 lp 非法？

// int i = 42;
// void* p = &i;
// long* lp = &i;
// 解：

// void *是从C语言那里继承过来的，可以指向任何类型的对象。 而其他指针类型必须要与所指对象严格匹配
// 因为lp的类型不是int，而void定义了一个空指针，可以接受任意类型的对象


// 25.
// 说明下列变量的类型和值

// (a) int* ip, i, &r = i;
// (b) int i, *ip = 0;
// (c) int* ip, ip2;
// 解：

// (a): ip 是一个指向 int 的指针, i 是一个 int, r 是 i 的引用
// (b): i 是 int , ip 是一个空指针。
// (c): ip 是一个指向 int 的指针, ip2 是一个 int



// 26.

// 下面哪些语句是合法的？如果不合法，请说明为什么？

// 解：

// const int buf;      // 不合法, const 对象必须初始化
// int cnt = 0;        // 合法
// const int sz = cnt; // 合法
// ++cnt; ++sz;        // 不合法, const 对象不能被改变


// 27.
// 下面的哪些初始化是合法的？请说明原因。

// 解：

// int i = -1, &r = 0;         // 不合法, r 必须引用一个对象
// int *const p2 = &i2;        // 合法，常量指针
// const int i = -1, &r = 0;   // 合法
// const int *const p3 = &i2;  // 合法
// const int *p1 = &i2;        // 合法
// const int &const r2;        // 不合法, r2 是引用，引用没有顶层 const
// const int i2 = i, &r = i;   // 合法

a:引用r的赋值对象必须是一个对象，所以不合法

b:合法，将p2设为一个常量指针，初始化为i2对象的地址

c:合法，将i设为常量，r设置为常量的引用（注意const   int   &r = 0  是正确的，但是int  &r = 0是不正确的）

d:合法，p3为指向常量的常量指针，初始值为i2的地址
<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp

e:合法，p1为指向常量的指针，初始值为i2的地址

f:使用不合法

=======

e:合法，p1为指向常量的指针，初始值为i2的地址

f:使用不合法

>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp
g:合法，正常的赋值。

// 28.
// 说明下面的这些定义是什么意思，挑出其中不合法的。

// 解：

// int i, *const cp;       // 不合法, const 指针必须初始化
// int *p1, *const p2;     // 不合法, const 指针必须初始化
// const int ic, &r = ic;  // 不合法, const int 必须初始化
// const int *const p3;    // 不合法, const 指针必须初始化
// const int *p;           // 合法. 一个指针，指向 const int
a:不合法，常量指针cp未初始化
<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp

b:不合法，常量指针p2未初始化

c:不合法，常量ic未初始化

d:不合法，常量指针p3未初始化

=======

b:不合法，常量指针p2未初始化

c:不合法，常量ic未初始化

d:不合法，常量指针p3未初始化

>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp
e:合法

// 29.
// 假设已有上一个练习中定义的那些变量，则下面的哪些语句是合法的？请说明原因。

// 解：

// i = ic;     // 合法, 常量赋值给普通变量
// p1 = p3;    // 不合法, p3 是const指针不能赋值给普通指针
// p1 = &ic;   // 不合法, 普通指针不能指向常量
// p3 = &ic;   // 合法, p3 是常量指针且指向常量
// p2 = p1;    // 合法, 可以将普通指针赋值给常量指针
// ic = *p3;   // 合法, 对 p3 取值后是一个 int 然后赋值给 ic
a:合法
<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp

b:不合法，const int 和 int 不是一个类型，指向常量的指针在赋值时必须类型一致

c:和b相同

=======

b:不合法，const int 和 int 不是一个类型，指向常量的指针在赋值时必须类型一致

c:和b相同

>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp
d:不合法，p3是一个常量指针，不能被再次赋值

e:不合法，p2是一个常量指针，不能被再次赋值

f:不合法，ic是个常量，不能被再次赋值



// 30.
对于下面的这些语句，请说明对象被声明成了顶层const还是底层const？

const int v2 = 0; int v1 = v2;
int *p1 = &v1, &r1 = v1;
const int *p2 = &v2, *const p3 = &i, &r2 = v2;
解：

v2 是顶层const，p2 是底层const，p3 既是顶层const又是底层const，r2 是底层const。

涉及知识点：

顶层const:指的是本身不可以被改变。

底层const:指的是自身所指对象不可以被改变。


用于声明引用的const都是底层const


v2是顶层const；

p2是底层const；

p3最左是底层，右侧是顶层const；

其他都不是const;




// 31.                      
假设已有上一个练习中所做的那些声明，则下面的哪些语句是合法的？请说明顶层const和底层const在每个例子中有何体现。

解：

r1 = v2; // 合法, 顶层const在拷贝时不受影响
p1 = p2; // 不合法, p2 是底层const，如果要拷贝必须要求 p1 也是底层const
p2 = p1; // 合法, int* 可以转换成const int*
p1 = p3; // 不合法, p3 是一个底层const，p1 不是
p2 = p3; // 合法, p2 和 p3 都是底层const，拷贝时忽略掉顶层const

知识点：顶层const的拷贝不受限制，但是底层const的拷贝的对象必须具有相同的底层const资格。一般来说：非常量可以赋值给常量，反之则不行

<<<<<<< HEAD:c++_practice_题目/src/c++_prime_questions_chapter_2.cpp

答案：

=======

答案：

>>>>>>> 8ca32d5184cb852fee6cc29515709a7d218d67fc:c++_practice/src/c++_prime_questions_chapter_2.cpp
a:合法；

b:不合法，p1是非常量，p2是常量，不能进行赋值操作；

c:合法；

d:不合法，p3既是底层也是顶层const，所以都得考虑到；

e:合法；

// 32.
// 面的代码是否合法？如果非法，请设法将其修改正确。

int null = 0, *p = null;
// 合法。指针可以初始化为 0 表示为空指针。



// 33.
利用本节定义的变量，判断下列语句的运行结果。

解：

a=42; // a 是 int
b=42; // b 是一个 int,(ci的顶层const在拷贝时被忽略掉了)
c=42; // c 也是一个int
d=42; // d 是一个 int *,所以语句非法
e=42; // e 是一个 const int *, 所以语句非法
g=42; // g 是一个 const int 的引用，引用都是底层const，所以不能被赋值


// 34.




// 35.
判断下列定义推断出的类型是什么，然后编写程序进行验证。

const int i = 42;
auto j = i; const auto &k = i; auto *p = &i; 
const auto j2 = i, &k2 = i;
解：

j 是 int，k 是 const int的引用，p 是const int *，j2 是const int，k2 是 const int 的引用

第一个auto  j  类型为int

第二个auto  &k 类型为const int &

第三个auto *p类型为const int *

第四个auto j2类型为const int

第五个auto &k2 类型为const int&



// 36.
关于下面的代码，请指出每一个变量的类型以及程序结束时它们各自的值。

int a = 3, b = 4;
decltype(a) c = a;
decltype((b)) d = a;
++c;
++d;
解：

c 是 int 类型，值为 4。d 是 int & 类型，绑定到 a，a 的值为 4 
decltype(())双层括号表示引用（注意引用必须初始化）
a是int类型   4

b是int类型   4

c是int类型   4

d是int &类型    4

全是4！！！！！！！！！！！

// 37.
关于下面的代码，请指出每一个变量的类型以及程序结束时它们各自的值。

int a = 3, b = 4;
decltype(a) c = a;
decltype((b)) d = a;
++c;
++d;
解：

c 是 int 类型，值为 4。d 是 int & 类型，绑定到 a，a 的值为 4 
知识点：赋值的表达式语句本身是一种引用：

a int 3;

b int 4;

c int 3;

d int & 3;




// 38.
说明由decltype 指定类型和由auto指定类型有何区别。请举一个例子，decltype指定的类型与auto指定的类型一样；再举一个例子，decltype指定的类型与auto指定的类型不一样。

解：

decltype 处理顶层const和引用的方式与 auto不同，decltype会将顶层const和引用保留起来。

int i = 0, &r = i;
//相同
auto a = i;
decltype(i) b = i;

//不同 d 是一个 int&
auto c = r;
decltype(r) d = r;





// 39.
编译下面的程序观察其运行结果，注意，如果忘记写类定义体后面的分号会发生什么情况？记录下相关的信息，以后可能会有用。

struct Foo { /* 此处为空  */ } // 注意：没有分号
int main()
{
    return 0;
}。
解：

提示应输入分号。

[Error] expected ';' after struct definition



int main()
{
   
    printf("hello c++ \n");
}